#include "virtual_uart.h"

//定义一个FIFO，用于模拟串口的接收FIFO
static DEFINE_KFIFO(rx_fifo, char, 128);
//接收标志，非0表示开启接收
uint8_t rx_flag = 0;
//模拟串口接收完成中断
static void rx_isr_work(struct work_struct *w);
DECLARE_WORK(rx_work, rx_isr_work);

//定义一个FIFO，用于模拟串口的发送FIFO
static DEFINE_KFIFO(tx_fifo, char, 128);
//发送标志，非0表示开启发送
uint8_t tx_flag = 0;
//模拟串口发送完成中断
static void tx_isr_work(struct work_struct *w);
DECLARE_WORK(tx_work, tx_isr_work);

//UART端口
struct uart_port *virt_port;

//proc文件，用于模拟串口硬件首发数据
static struct proc_dir_entry *proc_file;

//读取串口发送出去的数据，用于模拟硬件发送操作
static ssize_t proc_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	unsigned int copied;

	//读取串口发送的数据，模拟硬件发送
	kfifo_to_user(&tx_fifo, buf, size, &copied);

	//调度工作队列，模拟产生发送中断
	schedule_work(&tx_work);

	return copied;
}

//向串口写入数据，用于模拟硬件接收操作
static ssize_t proc_write (struct file *file, const char __user *buf, size_t size, loff_t *off)
{
	unsigned int copied;

	//将数据写入接收FIFO，模拟硬件接收
	kfifo_from_user(&rx_fifo, buf, size, &copied);

	//调度工作队列，模拟产生接收中断
	schedule_work(&rx_work);

	return copied;
}

static const struct file_operations proc_fops = {
	.read = proc_read,
	.write = proc_write,
};

//虚拟串口接收完成中断
static void rx_isr_work(struct work_struct *w)
{
	int rx_count;
	int result;
	unsigned long flags;
	uint8_t buffer[16];
	struct tty_port *ttyport = &virt_port->state->port;

	if(rx_flag)
	{
		while(1)
		{
			//从接收FIFO中读取数据
			rx_count = kfifo_out(&rx_fifo, buffer, sizeof(buffer));
			if(rx_count <= 0)
				break;

			//获取自旋锁
			spin_lock_irqsave(&virt_port->lock, flags);

			//将接收的数据写入行规程
			result = tty_insert_flip_string(ttyport, buffer, rx_count);
			//更新统计数据
			virt_port->icount.rx += result;

			//释放自旋锁
			spin_unlock_irqrestore(&virt_port->lock, flags);

			//通知行规程进行处理
			tty_flip_buffer_push(ttyport);
		}
	}

}

//虚拟串口发送完成中断
static void tx_isr_work(struct work_struct *w)
{
	int one;
	int two;
	int count;
	int tx_count;
	unsigned long flags;
	struct circ_buf *xmit = &virt_port->state->xmit;

	tx_count = 0;
	//获取自旋锁
	spin_lock_irqsave(&virt_port->lock, flags);

	//获取环形缓冲区的长度
	count = uart_circ_chars_pending(xmit);

	if(count > 0)
	{

		//将端口环形缓冲区的数据写入发送FIFO
		if (xmit->tail < xmit->head) {
			tx_count = kfifo_in(&tx_fifo, &xmit->buf[xmit->tail], count);
		} else {
			one = UART_XMIT_SIZE - xmit->tail;
			if (one > count)
				one = count;
			two = count - one;

			tx_count = kfifo_in(&tx_fifo, &xmit->buf[xmit->tail], one);
			if((two > 0) && (tx_count >= one))
				tx_count += kfifo_in(&tx_fifo, &xmit->buf[0], two);
		}

		//更新环形缓冲区
		xmit->tail = (xmit->tail + tx_count) & (UART_XMIT_SIZE - 1);

		//更新统计数据
		virt_port->icount.tx += tx_count;

		//检查发送是否完成
		if(tx_count >= count)
			tx_flag = 0;
	}
	else
		tx_flag = 0;

	//释放自旋锁
	spin_unlock_irqrestore(&virt_port->lock, flags);

}

//发送是否空闲
static unsigned int virt_uart_tx_empty(struct uart_port *port)
{
	/* 因为要发送的数据瞬间存入buffer */
	return (!tx_flag) ? 1 : 0;
}

//配置流控
static void virt_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
}

//获取流控配置
static unsigned int virt_uart_get_mctrl(struct uart_port *port)
{
	return 0;
}

//停止发送
static void virt_uart_stop_tx(struct uart_port *port)
{
	tx_flag = 0;
}

//启动发送
static void virt_uart_start_tx(struct uart_port *port)
{
	tx_flag = 1;
	//调度工作队列，模拟产生发送中断
	schedule_work(&tx_work);
}

//停止接收
static void virt_uart_stop_rx(struct uart_port *port)
{
	rx_flag = 0;
}

//传输控制中断信号
static void virt_uart_break_ctl(struct uart_port *port, int break_state)
{
}

//启动串口
static int virt_uart_startup(struct uart_port *port)
{
	rx_flag = 1;

	return 0;
}

//关闭串口
static void virt_uart_shutdown(struct uart_port *port)
{
	rx_flag = 0;
	tx_flag = 0;
}

//刷新输出缓冲区
static void virt_uart_flush_buffer(struct uart_port *port)
{
}

//配置串口
static void virt_uart_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old)
{
}

//获取端口类型
static const char *virt_uart_type(struct uart_port *port)
{
	return (port->type == PORT_8250) ? "VIRTUAL_UART" : NULL;
}

//释放端口
static void virt_uart_release_port(struct uart_port *port)
{
}

//请求端口
static int virt_uart_request_port(struct uart_port *port)
{
	return 0;
}

//配置端口
static void virt_uart_config_port(struct uart_port *port, int flags)
{
	if (flags & UART_CONFIG_TYPE)
		port->type = PORT_8250;
}

//验证端口
static int virt_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
{
	return -EINVAL;
}

//串口端口
static const struct uart_ops virt_uart_ops = {
	.tx_empty = virt_uart_tx_empty,
	.set_mctrl = virt_uart_set_mctrl,
	.get_mctrl = virt_uart_get_mctrl,
	.stop_tx = virt_uart_stop_tx,
	.start_tx = virt_uart_start_tx,
	.stop_rx = virt_uart_stop_rx,
	.break_ctl = virt_uart_break_ctl,
	.startup = virt_uart_startup,
	.shutdown = virt_uart_shutdown,
	.flush_buffer = virt_uart_flush_buffer,
	.set_termios = virt_uart_set_termios,
	.type = virt_uart_type,
	.release_port = virt_uart_release_port,
	.request_port = virt_uart_request_port,
	.config_port = virt_uart_config_port,
	.verify_port = virt_uart_verify_port,
};

//console发送函数
static void virt_uart_console_write(struct console *co, const char *s, unsigned int count)
{
	//将数据写入发送FIFO
	kfifo_in(&tx_fifo, s, count);
}

//获取console所属的tty_driver
struct tty_driver *virt_uart_console_device(struct console *co, int *index)
{
	struct uart_driver *p = co->data;
	*index = co->index;
	return p->tty_driver;
}

//配置console
static int virt_uart_console_setup(struct console *co, char *options)
{
	return 0;
}

//串口console
static struct uart_driver virt_uart_drv;
static struct console virt_uart_console = {
	.name = "ttyVIRT",
	.device = virt_uart_console_device,
	.write = virt_uart_console_write,
	.setup = virt_uart_console_setup,
	.flags = CON_PRINTBUFFER,
	.index = -1,
	.data = &virt_uart_drv,
};

//串口驱动
static struct uart_driver virt_uart_drv = {
	.owner = THIS_MODULE,
	.driver_name = "VIRT_UART",
	.dev_name = "ttyVIRT",
	.major = 0,
	.minor = 0,
	.nr = 1,
	.cons = &virt_uart_console,
};

//设备和驱动匹配成功执行
static int virtual_uart_probe(struct platform_device *pdev)
{
	int result;

	printk("%s\r\n", __FUNCTION__);

	//分配端口
	virt_port = devm_kzalloc(&pdev->dev, sizeof(struct uart_port), GFP_KERNEL);
	if(!virt_port)
	{
		printk("alloc memory failed\r\n");
		return -ENOMEM;
	}

	//设置端口
	virt_port->line = 0;
	virt_port->dev = &pdev->dev;
	//为让其执行console注册操作
	virt_port->mapbase = 1;
	virt_port->membase = 0;
	virt_port->type = PORT_8250;
	virt_port->iotype = UPIO_MEM;
	virt_port->irq = 0;
	virt_port->fifosize = 32;
	virt_port->ops = &virt_uart_ops;
	virt_port->rs485_config = NULL;
	//执行自动配置，但不探测UART类型
	virt_port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_TYPE;

	//添加端口
	result = uart_add_one_port(&virt_uart_drv, virt_port);
	if(result < 0)
	{
		printk("add uart port failed\n");
		return result;
	}

	//创建proc文件
	proc_file = proc_create("virt_uart", 0, NULL, &proc_fops);
	if (!proc_file)
	{
		uart_remove_one_port(&virt_uart_drv, virt_port);
		printk("create proc file failed\n");
		return -ENOMEM;
	}

	return 0;
}

//设备或驱动卸载时执行
static int virtual_uart_remove(struct platform_device *pdev)
{
	printk("%s\r\n", __FUNCTION__);

	//删除proc文件
	proc_remove(proc_file);
	//移除端口
	return uart_remove_one_port(&virt_uart_drv, virt_port);
}

/* 匹配列表，用于设备树和平台驱动匹配 */
static const struct of_device_id virtual_uart_of_match[] = {
	{.compatible = "atk,virtual_uart"},
	{ /* Sentinel */ }
};
//平台驱动
static struct platform_driver virtual_uart_drv = {
	.driver = {
		.name = "virtual_uart",
		.owner = THIS_MODULE,
		.pm = NULL,
		.of_match_table = virtual_uart_of_match,
	},
	.probe = virtual_uart_probe,
	.remove = virtual_uart_remove,
};

static int __init virtual_uart_init(void)
{
	int result;

	printk("%s\r\n", __FUNCTION__);

	//注册串口驱动
	result = uart_register_driver(&virt_uart_drv);
	if(result < 0)
	{
		printk("register cdev failed\r\n");
		return result;
	}

	//注册平台驱动
	result = platform_driver_register(&virtual_uart_drv);
	if(result < 0)
	{
		uart_unregister_driver(&virt_uart_drv);
		printk("add cdev failed\r\n");
		return result;
	}

	return 0;
}

static void __exit virtual_uart_exit(void)
{
	printk("%s\r\n", __FUNCTION__);

	//注销平台驱动
	platform_driver_unregister(&virtual_uart_drv);
	//注销串口驱动
	uart_unregister_driver(&virt_uart_drv);
}

module_init(virtual_uart_init);
module_exit(virtual_uart_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("LF");
MODULE_DESCRIPTION("virtual_uart_dev");
